﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ThicknessLibrary
{
    public static class DataOperator
    {
        #region 成员
        #endregion

        #region 属性
        public static double WidthDlarmValueStart { get; set; } = 0;
        public static double WidthDlarmValueEnd { get; set; } = 0;
        public static double HeightDlarmValueStart { set; get; } = 0;
        public static double HeightDlarmValueEnd { set; get; } = 0;
        #endregion

        #region 函数

        /// <summary>
        /// 数据预处理
        /// </summary>
        /// <returns></returns>
        public static List<double> PretreatmentData(float[] X_ProfileData, float[] Z_ProfileData, double BaseHeight)
        {
            if (X_ProfileData == null || Z_ProfileData == null)
                return null;

            List<float> Xlist = X_ProfileData.ToList();
            List<float> Zlist = Z_ProfileData.ToList();

            List<double> temp = new List<double>();
            for (int i = 0; i < Zlist.Count; i++)
            {
                Zlist[i] = (float)(Zlist[i] - BaseHeight);
                if (Zlist[i] <= 0)
                    Zlist[i] = 0;

                temp.Add(Zlist[i]);
            }
            Zlist.Clear();
            Xlist.Clear();
            return temp;
        }
        /// <summary>
        /// 数据平滑
        /// </summary>
        /// <param name="zList"></param>
        /// <returns></returns>
        public static List<double> DataSmooth(List<double> zList, int DataFilteValue, int Amplifier)
        {
            List<double> newZList = new List<double>();
            newZList = MedianFilter(zList.ToArray(), step: DataFilteValue).ToList();

            for(int i = 0; i < newZList.Count; i++)
                newZList[i] *= Amplifier;

            return newZList;
        }
        /// <summary>
        /// 移动平均,曲线平滑
        /// </summary>
        /// <param name="rawData">原曲线数组</param>
        /// <param name="step">步长</param>
        /// <returns></returns>
        public static double[] Smoothing(double[] rawData, int step = 3)
        {
            double[] smooth = new double[rawData.Length];
            unsafe
            {
                fixed (double* o = smooth, r = rawData)
                {
                    for (int i = step; i < rawData.Length; i++)
                    {
                        double total = 0;
                        int s = step * 2 + 1;
                        for (int j = i - step; j < i + step + 1; j++)
                        {
                            if (j < rawData.Length)
                            {
                                total += r[j];
                            }
                            else
                            {
                                break;
                            }
                        }
                        o[i] = total / s;
                    }
                    //Head fill
                    for (int i = 0; i < step; i++)
                    {
                        o[i] = o[step];
                    }
                    //Tail fill
                    int tail = rawData.Length - (rawData.Length % (step + 1)) - 1;
                    for (int j = tail; j < rawData.Length; j++)
                    {
                        o[j] = o[tail - 1];
                    }
                }
            }
            return smooth;
        }
        /// <summary>
        /// 中值滤波,去毛刺
        /// </summary>
        /// <param name="rawData"></param>
        /// <param name="step"></param>
        /// <returns></returns>
        public static double[] MedianFilter(double[] rawData, int step = 3)
        {
            int length = step * 2 + 1;
            double[] smooth = new double[rawData.Length];
            double[] median = new double[length];
            unsafe
            {
                fixed (double* o = smooth, r = rawData, m = median)
                {
                    for (int i = step; i < rawData.Length; i++)
                    {
                        int s = i - step;
                        int k = 0;
                        for (int j = i - step; j < i + step + 1; j++)
                        {
                            if (j < rawData.Length)
                            {
                                m[k] = r[j];
                            }
                            else
                            {
                                break;
                            }
                            k++;
                        }
                        o[i] = SortBubbleAscendingOrder(median)[step];//排序取中间值,在我的上一篇博客有源码
                    }
                    //Head fill
                    for (int i = 0; i < step; i++)
                    {
                        o[i] = o[step];
                    }
                    //Tail fill
                    int tail = rawData.Length - (rawData.Length % (step + 1)) - 1;
                    for (int j = tail; j < rawData.Length; j++)
                    {
                        o[j] = o[tail - 1];
                    }
                }
            }
            return smooth;
        }
        /// <summary>
        /// 冒泡升序
        /// </summary>
        /// <param name="rawData"></param>
        /// <returns></returns>
        public static double[] SortBubbleAscendingOrder(double[] rawData)
        {
            double[] outResult = new double[rawData.Length];
            unsafe
            {
                fixed (double* o = outResult, r = rawData)
                {
                    for (int i = 0; i < rawData.Length; i++)
                    {
                        o[i] = r[i];
                        for (int j = i; j > 0; j--)
                        {
                            if (o[j] < o[j - 1])
                            {
                                double t = o[j];
                                o[j] = o[j - 1];
                                o[j - 1] = t;
                            }
                        }
                    }
                }
            }
            return outResult;
        }
        /// <summary>
        /// 冒泡降序
        /// </summary>
        /// <param name="rawData"></param>
        /// <returns></returns>
        public static double[] SortBubbleDescendingOrder(double[] rawData)
        {
            double[] outResult = new double[rawData.Length];
            unsafe
            {
                fixed (double* o = outResult, r = rawData)
                {
                    for (int i = 0; i < rawData.Length; i++)
                    {
                        o[i] = r[i];
                        for (int j = i; j > 0; j--)
                        {
                            if (o[j] > o[j - 1])
                            {
                                double t = o[j];
                                o[j] = o[j - 1];
                                o[j - 1] = t;
                            }
                        }
                    }
                }
            }
            return outResult;
        }
        /// <summary>
        /// 减采样
        /// </summary>
        /// <param name="zlist"></param>
        /// <returns></returns>
        public static List<double> DownSample(List<double> zlist, int DownSample)
        {
            if (zlist == null || zlist.Count == 0)
                return null;
            if (DownSample == 0)
                return zlist;
            List<double> tempList = new List<double>();

            #region 降低采样
            for (int i = 0; i < zlist.Count; i++)
            {
                if (i % DownSample == 1)
                {
                    tempList.Add(zlist[i]);
                }
            }
            #endregion

            return tempList;
        }
        /// <summary>
        /// 数据滤波
        /// </summary>
        /// <param name="zlist"></param>
        /// <param name="filte">3、5、7、9</param>
        /// <returns></returns>
        public static List<double> DataFilte(List<double> zlist, int filte)
        {
            if (zlist == null || zlist.Count == 0)
                return null;
            if(filte == 1)
                return zlist;

            var kernel = filte / 2;

            #region 数据平滑
            //平均数据平滑
            List<double> tempList = new List<double>();
            for (int i = 0; i < zlist.Count; i++)
            {
                if (i > kernel - 1 && i < zlist.Count - kernel)
                {
                    double avg = 0;
                    for (int index = i - kernel; index < i + kernel + 1; index++)
                    {
                        avg += zlist[index];    
                    }
                    avg /= filte;
                    //var nce = Math.Pow(Math.Abs(avg - zlist[i]),3);
                    tempList.Add(avg);
                }
                else
                {
                    tempList.Add(zlist[i]);
                }
                tempList[i] = Math.Round(zlist[i], 3);
            }
            #endregion

            return zlist;
        }
        /// <summary>
        /// 二值化
        /// </summary>
        /// <param name="tempList"></param>
        /// <param name="lowValue"></param>
        /// <param name="HeightValue"></param>
        /// <returns></returns>
        public static List<double> Threshold(List<double> tempList, double lowValue, double HeightValue)
        {
            if(tempList == null || tempList.Count == 0) 
                return null;
            List<double> threshooldList = new List<double>();
            for (int i = 0; i < tempList.Count; i++)
            {
                if (tempList[i] > lowValue && tempList[i] < HeightValue)
                    threshooldList.Add(100);
                else
                    threshooldList.Add(0);
            }
            return threshooldList;
        }
        /// <summary>
        /// 检测边缘对 宽度信息
        /// </summary>
        /// <param name="XList"></param>
        /// <param name="thresholdList"></param>
        /// <param name="DownSampleValue"></param>
        /// <returns></returns>
        public static List<(double leftEdge, double rightEdge, double width, double Height)> DetectionEdge(
            List<double> XList, 
            List<double> ZList,
            List<double> thresholdList, 
            int DownSampleValue,
            double BaseLineValue)
        {
            if (XList == null || thresholdList == null || XList.Count == 0 || thresholdList.Count == 0)
                return null;
            List<(double leftEdge, double rightEdge, double width, double Height)> Edges = new List<(double leftEdge, double rightEdge, double width, double Height)>();

            List<int> RisingEdge = new List<int>();
            List<int> FallingEdge = new List<int>();
            for (int i = 0; i < thresholdList.Count - 1; i++)
            {
                if (thresholdList[i] == 0 && thresholdList[i + 1] == 100)
                    RisingEdge.Add(i);
                if (thresholdList[i] == 100 && thresholdList[i + 1] == 0)
                {
                    if (i < thresholdList.Count - 1)
                        FallingEdge.Add(i + 1);
                    else
                        FallingEdge.Add(i);
                }
            }
            if(RisingEdge.Count > FallingEdge.Count) //避免出现bug
            {
                RisingEdge.Remove(RisingEdge.Last());
            }

            for (int i = 0; i < RisingEdge.Count; i++)
            {
                double leftEdge = XList[RisingEdge[i] * (DownSampleValue == 0 ? 1 : DownSampleValue)];
                double rightEdge = XList[FallingEdge[i] * (DownSampleValue == 0 ? 1 : DownSampleValue)];
                double width = Math.Round(rightEdge - leftEdge, 3);

                double avg = 0;
                int start = RisingEdge[i] * (DownSampleValue == 0 ? 1 : DownSampleValue);
                int end = FallingEdge[i] * (DownSampleValue == 0 ? 1 : DownSampleValue);

                for (int index = start; index < end; index++)
                {
                    var value = ZList[index];
                    if (value < 0)
                        value = BaseLineValue;

                    avg += value;
                }
                avg /= (end - start);
                avg = Math.Round(avg, 3);
                avg -= BaseLineValue;

                Edges.Add((leftEdge, rightEdge, width, avg));
            }

            return Edges;
        }






        /// <summary>
        /// 确认边界
        /// </summary>
        /// <param name="X_ProfileData"></param>
        /// <param name="Z_ProfileData"></param>
        /// <param name="BaseHeight">39.3</param>
        public static List<double> Affirm(float[] X_ProfileData, float[] Z_ProfileData,
            double BaseHeight, int DownSample, double threshold)
        {
            if (X_ProfileData == null || Z_ProfileData == null)
                return null;

            List<float> Xlist = X_ProfileData.ToList();
            List<float> Zlist = Z_ProfileData.ToList();

            for (int i = 0; i < Zlist.Count; i++)
            {
                Zlist[i] = (float)(Zlist[i] - BaseHeight);
                if (Zlist[i] <= 0)
                    Zlist[i] = 0;

            }
            var avgValue = Zlist.Average();

            List<double> newZList = new List<double>();
            for (int i = 0; i < Zlist.Count; i++)
            {
                newZList.Add(Math.Pow(Zlist[i] - avgValue, 3) * 1000);
                if (newZList[i] <= 0)
                    newZList[i] = 0;
            }

            List<double> tempList = new List<double>();
            #region 降低采样
            for (int i = 0; i < newZList.Count; i++)
            {
                if (i % DownSample == 1)
                {
                    tempList.Add(newZList[i]);
                }
            }
            #endregion
            newZList.Clear();

            #region 数据平滑
            //平均数据平滑
            for (int i = 0; i < tempList.Count; i++)
            {
                if (i > 1 && i < tempList.Count - 2)
                {
                    var avg = (tempList[i - 2] + tempList[i - 1] + tempList[i] + tempList[i + 1] + tempList[i + 2]) / 5;
                    var nce = Math.Abs(avg - tempList[i]);
                    tempList[i] = avg;
                }
                else
                {
                    tempList[i] = tempList[i];
                }
                tempList[i] = Math.Round(tempList[i], 3);
                //tempList[i] = tempList[i] * 10000;
            }
            #endregion

            #region 对数据进行二值化处理
            List<int> ThresholdList = new List<int>();
            for (int i = 0; i < tempList.Count; i++)
            {
                if (tempList[i] > threshold)
                    ThresholdList.Add(1);
                else
                    ThresholdList.Add(0);
            }
            //检测上升沿和下降沿
            List<int> RisingEdge = new List<int>();
            List<int> FallingEdge = new List<int>();
            for (int i = 0; i < ThresholdList.Count - 1; i++)
            {
                if (ThresholdList[i] == 0 && ThresholdList[i + 1] == 1)
                    RisingEdge.Add(i);
                if (ThresholdList[i] == 1 && ThresholdList[i + 1] == 0)
                    FallingEdge.Add(i);
            }
            List<(double start, double end)> Edges = new List<(double start, double end)>(); //边缘对
            for (int i = 0; i < RisingEdge.Count; i++)
            {
                double startV = Xlist[RisingEdge[i] * 4];
                double endV = Xlist[FallingEdge[i] * 4];
                Edges.Add((startV, endV));
            }
            #endregion

            return tempList;
        }
        #endregion
    }
}
